import { ResultEnum, ContentTypeEnum } from "@/enums/httpEnum";
import { showErrorMessage, showHttpErrorMessage } from "./msg";
import { showLoading, hideLoading } from "./loading";
import useUserStore from "@/stores/user";
import { getToken } from "@/stores/auth";

interface FetchOptions {
    baseURL: string;
    method: string;
    key?: string;
    headers: Record<string, any>;
    body?: Record<string, any>;
    params?: Record<string, any>;
    retry?: number;
    timeout?: number;
    onRequest?: (data: any) => void;
    onResponse?: (data: any) => void;
    onResponseError?: (data: any) => void;
    showErrorMessage?: boolean;
    showSuccessMessage?: boolean;
    watch: boolean;
}

const requestConfig = {
    baseUrl: "/api/",
    // 超时时间
    timeout: 10000,
    // 请求头
    header: {
        "content-type": ContentTypeEnum.JSON,
    },
    // 是否需要loading加载
    loading: false,
    // 重试次数
    retryCount: 0,
};

// 后端返回通用结构
type Data<T> = {
    code: number;
    msg: string;
    data: T;
};

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type HandleRequestOptions = { request: Request; options: FetchOptions };
type HandleResponseOptions = { response: any };

// 检验登录过期
const checkLoginExpire = async(data: any) => {
    // 检验token过期重新登录
    if (data.code === ResultEnum.EXPIRE) {
        useUserStore().logout(false);
    }
};

// 请求拦截器
function handleRequest({ options }: HandleRequestOptions) {
    const {
        public: { VITE_APP_BASE_URL },
    } = useRuntimeConfig();

    if (!options.baseURL.length)
        options.baseURL = VITE_APP_BASE_URL + requestConfig.baseUrl;

    if (requestConfig.timeout) options.timeout = requestConfig.timeout;

    const token = getToken();
    // 请求头添加token
    if (token) options.headers.Authorization = token;
}

// 响应拦截器
function handleResponse({ response }: HandleResponseOptions) {
    if (response.status && response.status >= 200 && response.status < 300) {
        const apiData = response._data;
        if (apiData.code !== ResultEnum.SUCCESS) {
            showErrorMessage(apiData);
            checkLoginExpire(apiData);
        }
    } else {
        showHttpErrorMessage(response);
    }
}

const request = {
    get<T = any>(url: string, data?: any, header?: any, config?: any): Promise<T> {
        return request.request("GET", url, data, header, config);
    },
    post<T = any>(url: string, data?: any, header?: any, config?: any): Promise<T> {
        return request.request("POST", url, data, header, config);
    },
    put<T = any>(url: string, data?: any, header?: any, config?: any): Promise<T> {
        return request.request("PUT", url, data, header, config);
    },
    delete<T = any>(url: string, data?: any, header?: any, config?: any): Promise<T> {
        return request.request("DELETE", url, data, header, config);
    },
    upload<T = any>(
        url: string,
        name: string = "file",
        file: any,
        data?: any,
        callBack?: any
    ): Promise<T> {
        return new Promise((resolve, reject) => {
            const formData = new FormData();
            formData.append(name, file);

            console.log(formData)
            if (data) {
                Object.keys(data).forEach((key) => {
                    formData.append(key, data[key]);
                });
            }

            const options: FetchOptions | any = {
                baseURL: "",
                method: "POST",
                headers: {},
                body: formData,
                onRequest: handleRequest,
                onResponse: handleResponse,
                watch: false,
            };
            if (requestConfig.loading) showLoading();

            useFetch(url, options)
                .then((res) => {
                    if (res.data.value) {
                        const apiData = res.data.value as Data<T>;
                        if (apiData.code === ResultEnum.SUCCESS) {
                            if (callBack) callBack(res);
                            resolve(apiData.data);
                        } else {
                            reject(apiData.msg);
                        }
                    } else {
                        showErrorMessage(res.error.value);
                        reject(res.error.value);
                    }
                })
                .catch((error) => {
                    showErrorMessage({ msg: "网络错误，请稍后再试~" });
                    reject(error);
                }).finally(() => {
                    if (requestConfig.loading) hideLoading();
                });
        });
    },
    request<T = any>(
        method: HttpMethod,
        url: string,
        data?: any,
        header?: any,
        config?: any
    ): Promise<T> {
        return new Promise((resolve, reject) => {
            const options: FetchOptions | any = {
                baseURL: config?.baseURL || "",
                method: method,
                headers: {
                    ...header,
                    "Content-Type": requestConfig.header["content-type"],
                },
                onRequest: handleRequest,
                onResponse: handleResponse,
                watch: false,
            };
            if (requestConfig.loading || config?.loading) showLoading();

            if (data) {
                if (method === "GET" || method === "DELETE") {
                    options.params = data;
                } else {
                    options.body = data;
                }
            }

            useFetch(url, options)
                .then((res) => {
                    if (res.data.value) {
                        const apiData = res.data.value as Data<T>;
                        if (apiData.code === ResultEnum.SUCCESS) {
                            resolve(apiData.data);
                        } else {
                            reject(apiData.msg);
                        }
                    } else {
                        showErrorMessage(res.error.value);
                        reject(res.error.value);
                    }
                })
                .catch((error) => {
                    // 请求重试检验
                    let retryCount = isEmpty(config) ? requestConfig.retryCount : config?.retryCount;
                    if (retryCount > 0) {
                        request.request(method, url, data, header, { retryCount: retryCount - 1 });
                        return;
                    }
                    showErrorMessage({ msg: "网络错误，请稍后再试~" });
                    reject(error);
                }).finally(() => {
                    if (requestConfig.loading || config?.loading) hideLoading();
                });
        });
    },
};

export default request;
